﻿using System;
using System.Collections.Generic;
using System.Text;
using Silvermoon.Interfaces;
using Silvermoon.OpenGL.Native;
using System.Drawing;
using Silvermoon.OpenGL;
using Silvermoon.Utils;
using Silvermoon.Controls;

namespace Silvermoon.Shapes
{
    public class StringShape : RectangleShape, IColor
    {
        #region Fields

        private TextSpriteRange range = TextSpriteRange.Empty;
        private bool isShadowed;
        private TextSprite texture;
        private bool autoSize;

        #endregion
        #region ctor

        public StringShape()
            : base()
        {
            texture = CreateTextSprite();
            AutoSize = true;
            Color = Color.Empty;
        }


        public override void Dispose()
        {
            base.Dispose();
            texture.Dispose();
        }

        #endregion
        #region Properties


        /// <summary>
        /// Gets or sets the range of the characters to display.
        /// </summary>
        public TextSpriteRange Range
        {
            get { return range; }
            set
            {
                range = value;
            }
        }

        protected TextSprite TextSprite { get { return texture; } }

        /// <summary>
        /// Gets or sets the line mode.
        /// </summary>
        public LineMode LineMode
        {
            get { return texture.LineMode; }
            set
            {
                if (texture.LineMode != value)
                {
                    texture.LineMode = value;
                    OnInvalidateText();
                }
            }
        }

        /// <summary>
        /// Gets or sets the  horizontal alignment.
        /// </summary>
        public Alignment Alignment
        {
            get { return texture.Alignment; }
            set
            {
                if (texture.Alignment != value)
                {
                    texture.Alignment = value;
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// Gets or sets the line alignment
        /// </summary>
        public Alignment LineAlignment
        {
            get { return texture.LineAlignment; }
            set
            {
                if (texture.LineAlignment != value)
                {
                    texture.LineAlignment = value;
                    Invalidate();
                }
            }
        }

        public bool IsShadowed
        {
            get { return isShadowed; }
            set
            {
                if (isShadowed != value)
                {
                    isShadowed = value;
                    Invalidate();
                }
            }
        }

        /// <summary>
        /// Gets or sets the font to render.
        /// </summary>
        public FontSprite Font
        {
            get { return texture.Font; }
            set
            {
                if (texture.Font != value)
                {
                    texture.Font = value;
                    OnInvalidateText();
                }
            }
        }


        /// <summary>
        /// Gets the size that the text actually consumes.
        /// </summary>
        public Size TextSize { get { return texture.TextSize; } }


        /// <summary>
        /// Gets or sets the text to display
        /// </summary>
        public string Text
        {
            get { return texture.Text; }
            set
            {
                if (texture.Text != value)
                {
                    texture.Text = value;
                    OnInvalidateText();
                }
            }
        }

        /// <summary>
        /// If set to true, the size of the shape is determined by the text to render.
        /// </summary>
        public bool AutoSize
        {
            get { return autoSize; }
            set
            {
                if (autoSize != value)
                {
                    autoSize = value;
                    if (value) Alignment = Alignment.Near;
                    // if (value) texture.Size = new Size(int.MaxValue, int.MaxValue);
                    Invalidate();
                }
            }
        }

        public override Size Size
        {
            get
            {
                return autoSize ? texture.TextSize : texture.Size;
            }
            set
            {
                texture.Size = value;
                Invalidate();
            }
        }

        /// <summary>
        /// Gets or sets the skewness of the character. The bigger the value, the more italic the character appears.
        /// </summary>       
        public int Skew
        {
            get { return texture.Skew; }
            set
            {
                texture.Skew = value;
            }
        }


        /// <summary>
        /// Gets or sets the number of pixels between each character.
        /// </summary>
        public int CharSpace
        {
            get { return texture.CharSpace; }
            set { if (texture.CharSpace != value) { texture.CharSpace = value; Invalidate(); } }
        }

        /// <summary>
        /// Gets or sets the scale factor for the font.
        /// </summary>
        public float FontScale
        {
            get { return texture.FontScale; }
            set
            {
                if (texture.FontScale != value)
                {
                    texture.FontScale = value;
                    OnInvalidateText();
                }
            }
        }


        #endregion
        #region methods

        protected virtual TextSprite CreateTextSprite()
        {
            return new TextSprite();
        }

        protected override void Layout()
        {
            texture.PreLoad();
          //  if (autoSize) this.Size = texture.TextSize;
            base.Layout();
        }

        protected virtual void OnInvalidateText()
        {
            Invalidate();
        }

        protected override Shape CreateClone()
        {
            return new StringShape();
        }

        protected override void Copy(Shape shape)
        {
            base.Copy(shape);
            StringShape s = shape as StringShape;
            s.LineMode = LineMode;
            s.Alignment = Alignment;
            s.LineAlignment = LineAlignment;
            s.IsShadowed = isShadowed;
            s.Font = Font;
            s.Text = Text;
            s.AutoSize = AutoSize;
            s.CharSpace = CharSpace;
            s.FontScale = FontScale;
        }

        /// <summary>
        /// Gets the bounds for a given character.
        /// </summary>
        /// <param name="index">Index of character for which to get the rectangle.</param>
        /// <returns>Rectangle with the bounds of the character.</returns>
        public Rectangle GetCharRect(int index)
        {
            return texture.GetCharRect(index);
        }

        public override void Render(Silvermoon.Core.Renderer renderer)
        {
            if (string.IsNullOrEmpty(Text)) return;

            Color color = Color;
            if (color.IsEmpty) color = renderer.TextColor;
            //if (IsShadowed && !Font.IsShadowed)
            //{
            //    gl.Translatef(2f, 2f, 0f);
            //    int alpha = color.A * renderer.Alpha * Opacity / 255;
            //    texture.Color = alpha != 65025 ? ColorUtil.AlphaColor(ShadowColor, (alpha * ShadowColor.A / 65025)) : ShadowColor;
            //    texture.Render();
            //    gl.Translatef(-2f, -2f, 0f);
            //}
            {
                int alpha = renderer.Alpha * Opacity / (255);
                texture.Color = alpha < 254 ? ColorUtil.AlphaScaleColor(color, alpha) : color;
            }
            if (range.IsEmpty)
            {
                texture.Render();
            }
            else
            {
                texture.Render(range.Offset, range.Length);
            }
        }

        /// <summary>
        /// Gets the index of the character which is under a specified point.
        /// </summary>
        /// <param name="point">Point to determine. </param>
        /// <returns>Index of the character, otherwise -1.</returns>
        public int GetIndexFromPoint(Point point)
        {
            return texture.GetIndexFromPoint(point);
        }


        #endregion

    }
}
